﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace GEPSDevelopEnvironment.Common
{
    [Flags]
    enum ProcessAccessFlags : uint
    {
        All = 0x001F0FFF,
        Terminate = 0x00000001,
        CreateThread = 0x00000002,
        VMOperation = 0x00000008,
        VMRead = 0x00000010,
        VMWrite = 0x00000020,
        DupHandle = 0x00000040,
        SetInformation = 0x00000200,
        QueryInformation = 0x00000400,
        Synchronize = 0x00100000
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct PROCESS_BASIC_INFORMATION
    {
        public IntPtr ExitStatus;
        public IntPtr PebBaseAddress;
        public IntPtr AffinityMask;
        public IntPtr BasePriority;
        public UIntPtr UniqueProcessId;
        public IntPtr InheritedFromUniqueProcessId;

        public int Size
        {
            get { return (int)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); }
        }
    }

    class ProcessCommonUtils
    {
        public static string GetCommandLineOutput(string ACommandLine, out int ExitCode, 
            string AExeFile="", string AWorkingDirectory="", int milliseconds = 0)
        {
            ExitCode = 0;
            Process p = new Process();
            string res = string.Empty;
            if (AExeFile == "")
            {
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.Arguments = "/c " + ACommandLine;
            }
            else
            {
                p.StartInfo.FileName = AExeFile;
                p.StartInfo.Arguments = ACommandLine;
            }
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            if (AWorkingDirectory != "")
            {
                p.StartInfo.WorkingDirectory = AWorkingDirectory;
            }
            try
            {
                if (p.Start())
                {
                    if (milliseconds == 0)
                        p.WaitForExit();
                    else
                        p.WaitForExit(milliseconds);
                    res = p.StandardOutput.ReadToEnd();
                    ExitCode = p.ExitCode;
                    if (ExitCode != 0)
                    {
                        res += "\n" + p.StandardError.ReadToEnd();
                    }
                }
            }
            finally
            {
                if (p != null)
                    p.Close();
            }
            return res;
        }

        [DllImport("ntdll.dll", SetLastError = true)]
        static extern int NtQueryInformationProcess(IntPtr processHandle,
           int processInformationClass, IntPtr processInformation, uint processInformationLength,
           IntPtr returnLength);

        [DllImport("kernel32.dll")]
        static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);

        public static int GetParantPID(int APID)
        {
            IntPtr hProc = OpenProcess((ProcessAccessFlags)0x001F0FFF, false, APID);
            IntPtr pbi = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)));
            IntPtr outLong = Marshal.AllocHGlobal(sizeof(long));
            IntPtr outPtr = IntPtr.Zero;
            NtQueryInformationProcess(hProc, 0, pbi, 
                (uint)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), outLong);
            CloseHandle(hProc);
            Marshal.FreeHGlobal(outLong);
            Marshal.FreeHGlobal(pbi);
            return (int)((PROCESS_BASIC_INFORMATION)Marshal.PtrToStructure(pbi, typeof(PROCESS_BASIC_INFORMATION))).InheritedFromUniqueProcessId;
        }
    }
}
